/*
 * Copyright 2014 Walter Lütgenau.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package offset.nodes.client.dialog.menu.view;

/**
 * Parse a menu string.
 * 
 * Such a string may have sub menus. Each item may consist of a label, an icon and for
 * plain menu items, an action.
 * 
 * @author Walter Lütgenau
 */
public class MenuParser {
    public static final char ITEM_START = '(';
    public static final char ITEM_END = ')';
    public static final char DELIMITER = ',';
    public static final char ESCAPE = '\\';
    
    /** The menu string */
    String menu;
    /** The menu handler that reacts upon parser events */
    MenuHandler handler;
    
    public MenuParser(String menu, MenuHandler handler) {
        this.menu = menu;
        this.handler = handler;
    }
    
    /**
     * Stores information about an item.
     */
    class Item {
        String label;
        String icon;
        String action;
        
        public Item() {
            label = icon = action = null;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        public String getIcon() {
            return icon;
        }

        public void setIcon(String icon) {
            this.icon = icon;
        }

        public String getAction() {
            return action;
        }

        public void setAction(String action) {
            this.action = action;
        }
        
        /**
         * Add a string value. 
         * 
         * First the label, then optionally an icon and an action.
         * 
         * @param value the string value
         */
        public void addValue(String value) {
            if (label == null)
                label = value;
            else if (icon == null)
                icon = value;
            else if (action == null)
                action = value;
        }
        
        public String toString() {
            return label + " " + icon + " " + action;
        }
    }
    
    /**
     * Run the parsing.
     */
    public void parse() {
        StringBuilder buf = new StringBuilder();
        Item current = null;
        boolean inEscape = false;
        
        for (int i=0; i < menu.length(); i++) {
            char c = menu.charAt(i);
            
            switch(c) {
                case ESCAPE:
                    inEscape = true;
                    break;
                    
                case ITEM_START:
                    if (inEscape) {
                        inEscape = false;
                        buf.append(c);
                        break;
                    }
                    
                    if (current != null) {
                        current.addValue(buf.toString());
                        handler.startItem(current.getLabel(), current.getIcon(), current.getAction());
                    }
                    buf = new StringBuilder();
                    current = new Item();
                    break;
                    
                case DELIMITER:
                    if (inEscape) {
                        inEscape = false;
                        buf.append(c);
                        break;
                    }
                    
                    if (current != null)
                        current.addValue(buf.toString());
                    buf = new StringBuilder();
                    break;
                    
                case ITEM_END:
                    if (inEscape) {
                        inEscape = false;
                        buf.append(c);
                        break;
                    }
                    
                    if (current != null) {
                        current.addValue(buf.toString());
                        handler.startItem(current.getLabel(), current.getIcon(), current.getAction());
                        handler.endItem();
                        current = null;
                    } else
                        handler.endItem();
                    break;
                    
                default:
                    if (inEscape)
                        inEscape = false;
                    buf.append(c);
            }
        }
    }
}
